﻿using System;
using System.IO;
using WriteCSV;
using System.Collections.Generic;
using System.Linq;

namespace PMatch.Experimentation
{
	public static class ExperimentUtil
	{
		public static TimeSpan Time(this Action act)
		{
			// Se comenta esto para no requerir la compilacion con .NET Framework 4
			// de esta manera poder ejecutarlo en versiones de Mono mas accesibles a
			// muchas distribuciones de Linux			
			var now = DateTime.Now;
			act();
			var now2 = DateTime.Now;
			return now2 - now;
		}

		public static T Time<T>(this TextWriter log, string eventName, Func<T> action, out TimeSpan span)
		{
			var res = default(T);
			span = Time(() =>
			{
				res = action();
			});
			log.ReportTimeElapsed(eventName, span);
			return res;
		}

		public static T Time<T>(this TextWriter log, string eventName, Func<T> action)
		{
			TimeSpan span;
			return Time(log, eventName, action, out span);
		}

		public static void TimeAction(this TextWriter log, string eventName, Action action, out TimeSpan span)
		{
			Time(log, eventName, () => { action(); return 0; }, out span);
		}

		public static void TimeAction(this TextWriter log, string eventName, Action action)
		{
			Time(log, eventName, () => { action(); return 0; });
		}

		public static void ReportTimeElapsed(this TextWriter log, string eventName, TimeSpan span)
		{
			log.WriteLine("{0}: Took {1}", eventName, span);
		}

		public static void ReportTimeElapsed(this TimeSpan span, TextWriter log, string eventName)
		{
			ReportTimeElapsed(log, eventName, span);
		}

		public static CSVDocument ToDocument<T>(this IEnumerable<T> obj)
		{
			var doc = new CSVDocument();
			doc.Delimiter = ";";
			var t = typeof(T);
			var props = t.GetProperties();
			var cprops = props.OrderBy(x =>
			{
				var indexa = x.GetCustomAttributes(typeof(DocumentColumnIndex), true);
				var index = int.MaxValue;
				if (indexa != null && indexa.Length > 0) index = ((DocumentColumnIndex)indexa[0]).Index;
				return index;
			}).ToArray();
			int col = 0;
			foreach (var prop in cprops)
			{
				doc[0, col++] = prop.Name;
			}
			int row = 1;
			foreach (var item in obj)
			{
				for (col = 0; col < cprops.Length; col++)
				{
					doc[row, col] = cprops[col].GetValue(item, null);
				}
				row++;
			}
			return doc;
		}
	}

	[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
	sealed class DocumentColumnIndex : Attribute
	{
		public DocumentColumnIndex(int index)
		{
			this.index = index;
		}

		int index;
		public int Index { get { return index; } }
	}
}
